2012/05/02

Recent entries from same category

  1. Go 言語プログラミングエッセンスという本を書きました。
  2. errors.Join が入った。
  3. unsafe.StringData、unsafe.String、unsafe.SliceData が入った。
  4. Re: Go言語で画像ファイルか確認してみる
  5. net/url に JoinPath が入った。

BigQueryが正式版としてリリースされたようです。
Google、ビッグデータ分析サービス「BigQuery」を一般公開 - ITmedia ニュース

米Googleは11月14日(現地時間)、同社のクラウド上でいわゆる「ビッグデータ」を分析する企業向けサービス「Google BigQuery Service」のプレビュー版を公開したと発表した。正式版は有料になる見込みだが、現在は無料で利用できる。

http://www.itmedia.co.jp/news/articles/1111/15/news028.html
サンプルデータも幾つかある様で、githubのリポジトリ情報を格納している物もあったので試しにGo言語からクエリを発行して問い合わせてみた。 以下コード。 package main

import (
    "code.google.com/p/goauth2/oauth"
    "code.google.com/p/google-api-go-client/bigquery/v2"
    "encoding/gob"
    "fmt"
    "log"
    "net/http"
    "net/http/httptest"
    "net/url"
    "os"
    "os/exec"
    "path/filepath"
    "runtime"
    "time"
)

func osUserCacheDir() string {
    switch runtime.GOOS {
    case "darwin":
        return filepath.Join(os.Getenv("HOME"), "Library""Caches")
    case "linux""freebsd":
        return filepath.Join(os.Getenv("HOME"), ".cache")
    }
    log.Printf("TODO: osUserCacheDir on GOOS %q", runtime.GOOS)
    return "."
}

func tokenFromWeb(config *oauth.Config) *oauth.Token {
    ch := make(chan string)
    randState := fmt.Sprintf("st%d", time.Now())
    ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
        if req.URL.Path == "/favicon.ico" {
            http.Error(rw, ""404)
            return
        }
        if req.FormValue("state") != randState {
            log.Printf("State doesn't match: req = %#v", req)
            http.Error(rw, ""500)
            return
        }
        if code := req.FormValue("code"); code != "" {
            fmt.Fprintf(rw, "<h1>Success</h1>Authorized.")
            rw.(http.Flusher).Flush()
            ch <- code
            return
        }
        log.Printf("no code")
        http.Error(rw, ""500)
    }))
    defer ts.Close()

    config.RedirectURL = ts.URL
    authUrl := config.AuthCodeURL(randState)
    go openUrl(authUrl)
    log.Printf("Authorize this app at: %s", authUrl)
    code := <-ch
    log.Printf("Got code: %s", code)

    t := &oauth.Transport{
        Config:    config,
        Transport: http.DefaultTransport,
    }
    _, err := t.Exchange(code)
    if err != nil {
        log.Fatalf("Token exchange error: %v", err)
    }
    return t.Token
}

func openUrl(url string) {
    try := []string{"xdg-open""google-chrome""open"}
    for _, bin := range try {
        err := exec.Command(bin, url).Run()
        if err == nil {
            return
        }
    }
    log.Printf("Error opening URL in browser.")
}

func tokenCacheFile(config *oauth.Config) string {
    return filepath.Join(osUserCacheDir(), url.QueryEscape(
        fmt.Sprintf("go-api-demo-%s-%s-%s", config.ClientId, config.ClientSecret, config.Scope)))
}

func tokenFromFile(file string) (*oauth.Token, error) {
    f, err := os.Open(file)
    if err != nil {
        return nil, err
    }
    t := new(oauth.Token)
    err = gob.NewDecoder(f).Decode(t)
    return t, err
}

func saveToken(file string, token *oauth.Token) {
    f, err := os.Create(file)
    if err != nil {
        log.Printf("Warning: failed to cache oauth token: %v", err)
        return
    }
    defer f.Close()
    gob.NewEncoder(f).Encode(token)
}

func getOAuthClient(config *oauth.Config) *http.Client {
    cacheFile := tokenCacheFile(config)
    token, err := tokenFromFile(cacheFile)
    if err != nil {
        token = tokenFromWeb(config)
        saveToken(cacheFile, token)
    } else {
        log.Printf("Using cached token %#v from %q", token, cacheFile)
    }

    t := &oauth.Transport{
        Token:     token,
        Config:    config,
        Transport: http.DefaultTransport,
    }
    return t.Client()
}

func main() {

    var config = &oauth.Config{
        ClientId:     "XXXXXXXXXXXXX.apps.googleusercontent.com",
        ClientSecret: "YYYYYYYYYYYYYYYYYYYYYYYY",
        Scope:        bigquery.BigqueryScope,
        AuthURL:      "https://accounts.google.com/o/oauth2/auth",
        TokenURL:     "https://accounts.google.com/o/oauth2/token",
    }

    bigqueryService, err := bigquery.New(getOAuthClient(config))
    if err == nil {
        table, err := bigqueryService.Jobs.Query("XXXXXXXXXXXXX", &bigquery.QueryRequest {
            Query: "SELECT repository_description FROM [publicdata:samples.github_timeline] where repository_url = 'https://github.com/mattn/growl-for-linux'",
        }).Do()
        if err == nil {
            for _, row := range table.Rows {
                for _, f := range row.F {
                    println(f.V)
                }
            }
        }
    }
}
XXXXXXXXXXXXX にはプロジェクトIDを(ClientIDの一部になってるみたい)、YYYYYYYYYYYYYYYYYYYYYYYY には ClientSecret を埋めて実行して下さい。発行しているクエリは以下。 SELECT repository_description FROM [publicdata:samples.github_timeline] where repository_url = 'https://github.com/mattn/growl-for-linux'
これを実行すると以下のデータが得られた。 Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
実行はそれほど速くありませんでした。巨大なデータをオンラインで扱えるインフラとしては面白いかなーと思った。
ただ最近の API は OAuth な物が多く、実行するにはアクセストークンが必要になり、アクセストークンを得るにはブラウザを起動する必要がある。今回 Go言語のdatabase/sqlドライバの一つに加えようと思ってけどちょっと難しいかも。どっちかっていうとユーザ単位にアクセストークンを取らせる様なコンシューマサービス向けなのかな。
Posted at by